package com.example.apng;

import android.graphics.drawable.Drawable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 如果TextView被包裹在ScrollView中，那么当TextView关闭硬件加速时ScrollView也需要关闭硬件加速，否则可能画面白屏
 */
public abstract class AbstractApngTextViewHelper {
    private ScheduledFuture scheduledFuture = null;
    private int mApngTargetSize = -1;
    private boolean hasApng = false;//text里是否有符合要求的apng
    private TextView mHost;
    private Runnable task;

    private static ScheduledExecutorService pool;
    private static final int APNG_REFRESH_PERIOD_MS = 50;//apng刷新周期

    public static ScheduledExecutorService getScheduledExecutorService() {
        if (pool == null) {
            pool = new ScheduledThreadPoolExecutor(1,new ThreadPoolExecutor.DiscardPolicy());
            if(pool instanceof ThreadPoolExecutor){
                ((ThreadPoolExecutor) pool).setMaximumPoolSize(20);
            }
        }
        return pool;
    }

    public AbstractApngTextViewHelper(@NonNull TextView textView) {
        mHost = textView;
        mHost.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
            @Override
            public void onViewAttachedToWindow(View v) {
                if (hasApng) {
                    startTimer();
                }
            }

            @Override
            public void onViewDetachedFromWindow(View v) {
                stopTimer();
            }
        });
        task = () -> {
            if (mHost != null && mHost.isShown()) { //其实Invalidate内部会自动忽略不可见的
                mHost.postInvalidate();
            }
        };
    }


    /**
     * 获得匹配的正则表达式
     */
    public abstract Pattern getPattern();

    /**
     * 根据Pattern匹配得到的key获得相对应的图片资源
     */
    public abstract int getDrawableResId(String key);

    /**
     * 获得apng刷新周期，单位毫秒，例如50ms表示20帧
     *
     * @return
     */
    public int getApngRefreshPeriod() {
        return APNG_REFRESH_PERIOD_MS;
    }


    /**
     * @param content
     * @param apngTargetSize //-1表示默认
     */
    public void setText(CharSequence content, int apngTargetSize) {
        if (mHost == null) {
            return;
        }
        setApngTargetSize(apngTargetSize);
        mHost.setText(handleTextWithEmoji(content));
    }

    private CharSequence handleTextWithEmoji(CharSequence text) {
        if (mHost == null) {
            return text;
        }
        if (TextUtils.isEmpty(text)) {
            return text;
        }
        SpannableStringBuilder spannableString = new SpannableStringBuilder(text);
        Matcher matcherEmotion = getPattern().matcher(text);
        hasApng = false;
        while (matcherEmotion.find()) {
            String key = matcherEmotion.group();
            int imgRes = getDrawableResId(key);
            if (imgRes == -1) {
                continue;
            }
            int start = matcherEmotion.start();
            Drawable drawable = ApngDrawableManager.getInstance(mHost.getContext()).
                    getApngDrawable(imgRes, mApngTargetSize, mApngTargetSize);
            if (drawable != null) {
                hasApng = true;
            } else {
                drawable = ContextCompat.getDrawable(mHost.getContext(), imgRes);
                if(mApngTargetSize>0){
                    drawable.setBounds(0, 0, mApngTargetSize, mApngTargetSize);
                }
            }
            ImageSpan span = new CenterImageSpan(drawable);
            spannableString.setSpan(span, start, start + key.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

        if (hasApng) {
            startTimer();
        } else {
            stopTimer();
        }
        if (hasApng && mHost.isTextSelectable()) {
            mHost.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        } else {
            mHost.setLayerType(View.LAYER_TYPE_NONE, null);
        }
        return spannableString;
    }

    private void stopTimer() {
        if (scheduledFuture != null) {
            scheduledFuture.cancel(true);
        }
    }

    private void startTimer() {
        try {
            stopTimer();
            scheduledFuture = getScheduledExecutorService().scheduleAtFixedRate(task, 0, getApngRefreshPeriod(), TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @param targetSize -1表示默认
     */
    private void setApngTargetSize(int targetSize) {
        mApngTargetSize = targetSize;
    }
}